#!/usr/bin/env node

/**
 * 批量爬取工具 - 支持多关键词批量执行
 * 
 * 用法：
 *   node batch-crawl.js                           # 执行所有任务的所有关键词
 *   node batch-crawl.js --task amazon-de          # 只执行指定任务
 *   node batch-crawl.js --keywords "word1,word2"  # 自定义关键词
 *   node batch-crawl.js --loop                    # 无限循环执行
 *   node batch-crawl.js --loop --interval 3600    # 每小时执行一次
 */

const fs = require('fs');
const path = require('path');
const config = require('./tasks.config');
const dbConnection = require('./db/connection');

// 解析命令行参数
function parseArgs() {
    const args = process.argv.slice(2);
    const options = {
        task: null,                 // 指定任务
        keywords: null,             // 自定义关键词（逗号分隔）
        loop: false,                // 是否循环执行
        interval: 3600,             // 循环间隔（秒，默认1小时）
        delay: 5000,                // 关键词之间的延迟（毫秒）
        startFrom: 0,               // 从第几个关键词开始
        count: null,                // 只执行前N个关键词
        saveLog: true,              // 是否保存日志
    };

    for (let i = 0; i < args.length; i++) {
        const arg = args[i];

        if (arg === '--task' || arg === '-t') {
            options.task = args[++i];
        } else if (arg === '--keywords' || arg === '-k') {
            options.keywords = args[++i].split(',').map(k => k.trim());
        } else if (arg === '--loop' || arg === '-l') {
            options.loop = true;
        } else if (arg === '--interval' || arg === '-i') {
            options.interval = parseInt(args[++i]) || 3600;
        } else if (arg === '--delay' || arg === '-d') {
            options.delay = parseInt(args[++i]) || 5000;
        } else if (arg === '--start-from' || arg === '-s') {
            options.startFrom = parseInt(args[++i]) || 0;
        } else if (arg === '--count' || arg === '-c') {
            options.count = parseInt(args[++i]) || null;
        } else if (arg === '--no-log') {
            options.saveLog = false;
        } else if (arg === '--help' || arg === '-h') {
            console.log(`
批量爬取工具 - 支持多关键词批量执行

用法：
  node batch-crawl.js [选项]

选项：
  -t, --task <任务名>          指定要执行的任务（如 amazon-de）
  -k, --keywords <关键词>      自定义关键词，逗号分隔
  -l, --loop                   无限循环执行所有关键词
  -i, --interval <秒>          循环间隔时间（秒，默认：3600）
  -d, --delay <毫秒>           关键词之间的延迟（毫秒，默认：5000）
  -s, --start-from <索引>      从第几个关键词开始（默认：0）
  -c, --count <数量>           只执行前N个关键词
  --no-log                     不保存执行日志
  -h, --help                   显示帮助信息

示例：
  # 执行亚马逊德国的所有关键词
  node batch-crawl.js --task amazon-de

  # 自定义关键词
  node batch-crawl.js --task amazon-de --keywords "Baby Foods,Toys,Diapers"

  # 只执行前5个关键词
  node batch-crawl.js --task amazon-de --count 5

  # 从第3个关键词开始执行
  node batch-crawl.js --task amazon-de --start-from 3

  # 无限循环执行（每小时一次）
  node batch-crawl.js --task amazon-de --loop

  # 循环执行，每30分钟一次
  node batch-crawl.js --task amazon-de --loop --interval 1800

  # 快速测试（间隔2秒）
  node batch-crawl.js --task amazon-de --count 3 --delay 2000

提示：
  - 按 Ctrl+C 可随时停止执行
  - 关键词配置文件：keywords.config.js
  - 执行日志保存在：batch-crawl-logs/ 目录
            `);
            process.exit(0);
        }
    }

    return options;
}

// 批量执行统计
class BatchStatistics {
    constructor() {
        this.totalKeywords = 0;
        this.processedKeywords = 0;
        this.successKeywords = 0;
        this.failedKeywords = 0;
        this.errors = [];
        this.startTime = Date.now();
        this.results = [];
    }

    recordKeyword(keyword, success, error = null, details = null) {
        this.processedKeywords++;
        if (success) {
            this.successKeywords++;
        } else {
            this.failedKeywords++;
            if (error) {
                this.errors.push({
                    keyword: keyword,
                    error: error.message || String(error),
                    timestamp: new Date().toISOString()
                });
            }
        }
        
        this.results.push({
            keyword: keyword,
            success: success,
            error: error ? (error.message || String(error)) : null,
            details: details,
            timestamp: new Date().toISOString()
        });
    }

    getSuccessRate() {
        return this.processedKeywords > 0 
            ? ((this.successKeywords / this.processedKeywords) * 100).toFixed(2) 
            : 0;
    }

    getTotalTime() {
        return ((Date.now() - this.startTime) / 1000).toFixed(2);
    }

    printSummary() {
        console.log('\n' + '='.repeat(80));
        console.log('📊 批量执行统计摘要');
        console.log('='.repeat(80));
        console.log(`总关键词数: ${this.totalKeywords}`);
        console.log(`已处理:     ${this.processedKeywords}`);
        console.log(`成功:       ${this.successKeywords} ✅`);
        console.log(`失败:       ${this.failedKeywords} ❌`);
        console.log(`成功率:     ${this.getSuccessRate()}%`);
        console.log(`总耗时:     ${this.getTotalTime()} 秒`);
        
        if (this.errors.length > 0) {
            console.log('\n失败的关键词:');
            this.errors.forEach(err => {
                console.log(`  ❌ "${err.keyword}": ${err.error}`);
            });
        }
        console.log('='.repeat(80) + '\n');
    }

    saveToFile(task) {
        try {
            const logsDir = path.join(__dirname, 'batch-crawl-logs');
            if (!fs.existsSync(logsDir)) {
                fs.mkdirSync(logsDir, { recursive: true });
            }

            const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
            const filename = `batch_${task}_${timestamp}.json`;
            const filepath = path.join(logsDir, filename);

            const data = {
                summary: {
                    task: task,
                    totalKeywords: this.totalKeywords,
                    processedKeywords: this.processedKeywords,
                    successKeywords: this.successKeywords,
                    failedKeywords: this.failedKeywords,
                    successRate: this.getSuccessRate(),
                    totalTime: this.getTotalTime()
                },
                results: this.results,
                errors: this.errors,
                timestamp: new Date().toISOString()
            };

            fs.writeFileSync(filepath, JSON.stringify(data, null, 2), 'utf-8');
            console.log(`\n💾 执行日志已保存到: ${filepath}`);
        } catch (error) {
            console.error(`❌ 保存日志失败: ${error.message}`);
        }
    }
}

// 执行单个关键词
async function executeKeyword(task, keyword, index, total) {
    console.log('\n' + '━'.repeat(80));
    console.log(`🔍 [${index + 1}/${total}] 正在处理关键词: "${keyword}"`);
    console.log('━'.repeat(80) + '\n');

    try {
        // 动态设置环境变量
        process.env.CRAWL_KEYWORD = keyword;
        
        // 执行爬虫
        const TaskManager = require('./task-manager');
        const config = require('./tasks.config');
        
        // 加载任务
        const taskPath = path.join(__dirname, 'tasks', task, 'index.js');
        if (!fs.existsSync(taskPath)) {
            throw new Error(`任务 "${task}" 不存在`);
        }
        
        // 清除缓存，重新加载任务（确保使用最新的关键词）
        delete require.cache[require.resolve(taskPath)];
        const taskConfig = require(taskPath);
        
        // 创建任务管理器
        const manager = new TaskManager({
            headless: config.browser.headless,
            slowMo: config.browser.slowMo,
            stealth: config.browser.stealth,
        });
        
        // 执行任务
        manager.addTasks([taskConfig]);
        await manager.runParallel();
        await manager.close();
        
        console.log(`\n✅ 关键词 "${keyword}" 处理完成`);
        return { success: true };
        
    } catch (error) {
        console.error(`\n❌ 关键词 "${keyword}" 处理失败:`, error.message);
        return { success: false, error: error };
    } finally {
        // 清除环境变量
        delete process.env.CRAWL_KEYWORD;
    }
}

// 批量执行
async function batchCrawl(task, keywords, options) {
    const stats = new BatchStatistics();
    stats.totalKeywords = keywords.length;
    
    console.log('========================================');
    console.log(`    批量爬取 - ${task}`);
    console.log('========================================\n');
    
    console.log(`总关键词数: ${keywords.length}`);
    console.log(`开始索引:   ${options.startFrom}`);
    if (options.count) {
        console.log(`执行数量:   ${options.count}`);
    }
    console.log(`执行间隔:   ${options.delay}ms`);
    console.log(`\n关键词列表:`);
    keywords.forEach((kw, i) => {
        console.log(`  ${i + 1}. ${kw}`);
    });
    console.log('');
    
    // 处理起始位置和数量限制
    const startIndex = options.startFrom;
    const endIndex = options.count 
        ? Math.min(startIndex + options.count, keywords.length)
        : keywords.length;
    
    const keywordsToProcess = keywords.slice(startIndex, endIndex);
    
    for (let i = 0; i < keywordsToProcess.length; i++) {
        const keyword = keywordsToProcess[i];
        const globalIndex = startIndex + i;
        
        const result = await executeKeyword(task, keyword, globalIndex, keywords.length);
        stats.recordKeyword(keyword, result.success, result.error);
        
        // 打印当前进度
        console.log(`\n📊 当前进度: ${stats.processedKeywords}/${keywordsToProcess.length} (成功率: ${stats.getSuccessRate()}%)`);
        
        // 如果不是最后一个，等待间隔
        if (i < keywordsToProcess.length - 1) {
            console.log(`\n⏸️  等待 ${options.delay}ms 后处理下一个关键词...`);
            await new Promise(resolve => setTimeout(resolve, options.delay));
        }
    }
    
    return stats;
}

// 主函数
async function main() {
    const options = parseArgs();
    
    // 连接数据库（如果启用）
    if (config.database && config.database.enabled) {
        try {
            console.log('📊 正在连接数据库...');
            await dbConnection.connect();
            console.log('✅ 数据库连接成功');
        } catch (error) {
            console.error('⚠️  数据库连接失败:', error.message);
            if (!config.database.continueOnError) {
                console.error('❌ 数据库连接失败，程序终止');
                process.exit(1);
            } else {
                console.log('⚠️  将继续执行，但不会保存到数据库');
            }
        }
    }
    
    // 确定任务
    const task = options.task || 'amazon-de';
    
    // 获取关键词列表
    let keywords;
    if (options.keywords) {
        keywords = options.keywords;
        console.log(`使用自定义关键词 (${keywords.length} 个)`);
    } else if (config.keywords && config.keywords[task]) {
        keywords = config.keywords[task];
        console.log(`从配置文件加载关键词 (${keywords.length} 个)`);
    } else {
        console.error(`❌ 未找到任务 "${task}" 的关键词配置`);
        console.log(`💡 请在 tasks.config.js 的 keywords 部分添加配置或使用 --keywords 指定`);
        
        // 断开数据库连接
        if (config.database && config.database.enabled) {
            await dbConnection.disconnect();
        }
        
        process.exit(1);
    }
    
    if (keywords.length === 0) {
        console.error(`❌ 关键词列表为空`);
        
        // 断开数据库连接
        if (config.database && config.database.enabled) {
            await dbConnection.disconnect();
        }
        
        process.exit(1);
    }
    
    // 设置 Ctrl+C 处理
    let isRunning = true;
    process.on('SIGINT', async () => {
        console.log('\n\n⚠️  收到中断信号，正在停止...\n');
        isRunning = false;
        
        // 断开数据库连接
        if (config.database && config.database.enabled) {
            await dbConnection.disconnect();
        }
    });
    
    try {
        if (options.loop) {
            // 循环模式
            console.log(`\n🔄 循环模式已启用，每 ${options.interval} 秒执行一次`);
            console.log('按 Ctrl+C 停止\n');
            
            let loopCount = 0;
            while (isRunning) {
                loopCount++;
                console.log('\n' + '='.repeat(80));
                console.log(`🔄 第 ${loopCount} 轮执行`);
                console.log('='.repeat(80));
                
                const stats = await batchCrawl(task, keywords, options);
                stats.printSummary();
                
                if (options.saveLog) {
                    stats.saveToFile(`${task}_loop${loopCount}`);
                }
                
                if (isRunning) {
                    console.log(`\n⏸️  等待 ${options.interval} 秒后开始下一轮...\n`);
                    await new Promise(resolve => setTimeout(resolve, options.interval * 1000));
                }
            }
        } else {
            // 单次执行模式
            const stats = await batchCrawl(task, keywords, options);
            stats.printSummary();
            
            if (options.saveLog) {
                stats.saveToFile(task);
            }
        }
        
        console.log('🎉 批量执行完成！\n');
        
    } finally {
        // 确保断开数据库连接
        if (config.database && config.database.enabled) {
            await dbConnection.disconnect();
        }
    }
}

// 运行
if (require.main === module) {
    main().catch(async (error) => {
        console.error('❌ 执行过程中出现致命错误:', error);
        
        // 确保断开数据库连接
        if (config.database && config.database.enabled) {
            try {
                await dbConnection.disconnect();
            } catch (dbError) {
                console.error('⚠️  断开数据库连接时出错:', dbError.message);
            }
        }
        
        process.exit(1);
    });
}

module.exports = main;

